Basic structure of an OI4 OEC service
The oi4-oec-service is intended to cover as much of the OI4 OEC state machine as possible.
By just creating an instance of the IOI4Application
and providing the according configuration you will receive an (almost) OI4 OEC compliant application.
Of course, this application will not provide any useful information. The oi4-oec-service offers a couple of Interfaces and according default implementations.
Those default implementations are intended to be overridden to provide the application specific logic.
But we will come to all of that later...first things first.
The simplest OI4 OEC application
const applicationResources = new OI4ApplicationResources();
new OI4ApplicationFactory(applicationResources).build();
The provided code snipped will create an instance of the IOI4ApplicationResources
with the help of the default implementation OI4ApplicationResources
.
It assumes that the configuration is provided as described in Configuration of OEC services and a that there is a JSON file describing the MAM of the service present at /etc/oi4/config/mam.json
.
Not bad, right? But again, this service will not provide any useful information. But before we dive into details how to provide your own business logic and information, we will cover all major Interfaces, Classes, etc. that you should be aware of.
Overview of major Interfaces, Classes, etc.
IOI4Application - The core of an OI4 application
The Interface IOI4Application contains most of the business logic that is needed by the OI4 state machine. It will set up the MQTT connection, send the birth message, register the LWT message and subscribe to the relevant topics. It will also send the periodic health state. Furthermore, it offers a couple of methods to send messages to the broker.
The provided default implementation is the Class OI4Application. Typically, the default implementation should work.
In case you need to publish data regularly, e.g. if you provide an OT Connector, you can extend this class and add the publishing with a setInterval
. An example how to do that is available in the ServiceDemoOI4Application of the demo service.
Foreign messages
Sending an according response message to a GET request is handled by the oi4-service out of the box. If your application is subscribed an Event with the symbol foreignMessage
is emitted by the MqttMessageProcessor
.
The IOI4Application
offers an addListener
and removeListener
function that can be used to un/-subscribe to these events...
import {foreignMessage} from '../messaging/MqttMessageProcessor';
const application = new OI4ApplicationFactory(applicationResources, paths).initialize(builder).createOI4Application();
const listener = (topicInfo: TopicInfo, parsedMessage: IOPCUANetworkMessage): void => {
console.log(`Topic: ${topicInfo} Message: ${parsedMessage}`)
};
application.addListener(foreignMessage, listener)
application.removeListener(foreignMessage, listener)
IOI4ApplicationResources - The data provider
The Interface IOI4ApplicationResources it the pivotal data provider. Whenever an OI4 resource is requested (meaning a GET message has been received) the IOI4Application
will retrieve the data from the IOI4ApplicationResources
.
The default implementation is OI4ApplicationResources, but the class is meant to be overridden in case your service provides data. Your implementation should override the getters and setters of the individual properties.
The IOI4ApplicationResources
is derived from the Interface IOI4Resource, respectively OI4Resource.
An IOI4Resource
is equivalent to Source
in the OI4 OEC specification. It can be the application/service itself or an affiliated asset.
IOI4ApplicationFactory - The starting point
The Interface IOI4ApplicationFactory
and its implementation the OI4ApplicationFactory are the starting point for every OI4 application. The factory processes the configurations and create an instance of the IOI4Application
.
If you stay with the default settings paths, you just have to provide an IOI4ApplicationResources
of your application.
Typical starting points
The oi4-service has the intention to make your life with OI4 easier. Therefore, there is not that much to do, to get your application up and running. The Classes you will have to implement differ a bit, depending on the nature of your service. Either you provide data to the bus (e.g. an OT Connector), consume data from bus (e.g. a cloud connector) or you do both. Here are examples for the different cases.
OT Connector providing data
- Extend the Class
OI4ApplicationResources
to provide access to the assets (as SubResources). Here is an example for such a class. - Create an instance of your
OI4ApplicationResources
. - Extend the Class
OI4Application
to frequently provide your data like in this example. - Extend the Class
OI4ApplicationBuilder
and override the methodnewOI4Application
to return an instance of yourOI4Application
implementation; CLICK - Initialize the OI4ApplicationFactory with your
OI4ApplicationResources
and builder...const applicationFactory = new OI4ApplicationFactory(applicationResources).initialize(builder);
- Finally, create the
OI4Application
with...applicationFactory.createOI4Application();
OOCConnector consumer data
- Create an instance of
OI4ApplicationResources
. - Add listener to the
foreignMessage
event. - Add your additional subscriptions (in this example all MAM messages).
const applicationResources = new OI4ApplicationResources();
const application = new OI4ApplicationFactory(applicationResources, paths).initialize(builder).createOI4Application();
const listener = (topicInfo: TopicInfo, parsedMessage: IOPCUANetworkMessage): void => {
console.log(`Topic: ${topicInfo} Message: ${parsedMessage}`)
};
application.addListener(foreignMessage, listener)
await application.addSubscription('Oi4/OTConnector/+/+/+/+/Pub/MAM');
await application.addSubscription('Oi4/OTConnector/+/+/+/+/Pub/MAM/*');